package com.nhim.cms.admin.client.ctype.ui;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.google.gwt.activity.shared.Activity;
import com.google.gwt.cell.client.AbstractCell;
import com.google.gwt.cell.client.AbstractEditableCell;
import com.google.gwt.cell.client.Cell;
import com.google.gwt.cell.client.CheckboxCell;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.cell.client.TextCell;
import com.google.gwt.cell.client.TextInputCell;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.SpanElement;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.cellview.client.CellList;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.HasKeyboardPagingPolicy.KeyboardPagingPolicy;
import com.google.gwt.user.cellview.client.HasKeyboardSelectionPolicy.KeyboardSelectionPolicy;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.AbstractImagePrototype;
import com.google.gwt.user.client.ui.AcceptsOneWidget;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.ListDataProvider;
import com.google.gwt.view.client.ProvidesKey;
import com.google.gwt.view.client.SelectionChangeEvent;
import com.google.gwt.view.client.SingleSelectionModel;
import com.google.web.bindery.requestfactory.shared.Receiver;
import com.google.web.bindery.requestfactory.shared.ServerFailure;
import com.nhim.cms.admin.client.ScrollablePagerPanel;
import com.nhim.cms.admin.client.ctype.ui.ContentTypeElementDefinitionSelection.Listener;
import com.nhim.cms.admin.client.place.ContentTypePlace;
import com.nhim.cms.admin.client.rpc.ContentTypeElementDefinitionRPCService;
import com.nhim.cms.admin.client.rpc.ContentTypeElementDefinitionRPCServiceAsync;
import com.nhim.cms.admin.client.style.Styles;
import com.nhim.cms.admin.shared.ContentTypeElementDefinitionRPCProxy;
import com.nhim.cms.admin.shared.ContentTypeProxy;
import com.nhim.cms.admin.shared.ContentTypeRequest;
import com.nhim.cms.admin.shared.MessageManager;
import com.nhim.cms.admin.shared.NhimCMSAdminRequestFactory;

public class ContentType extends Composite implements Activity {
	
	private static ContentTypeUiBinder uiBinder = GWT
			.create(ContentTypeUiBinder.class);

	interface ContentTypeUiBinder extends
			UiBinder<Widget, ContentType> {
	}
	

	@UiField
	Button btnSave;
	@UiField
	Button btnDelete;
	@UiField
	Button btnNew;
	@UiField
	Anchor btnEdit;
	@UiField
	TextBox txtName;
	@UiField
	TextBox txtDescription;
	@UiField
	ScrollablePagerPanel pagerPanel;
	@UiField
	com.google.gwt.user.client.ui.HTMLPanel editPanel;
	@UiField
	com.google.gwt.user.client.ui.HTMLPanel overviewPanel;
	@UiField
	SpanElement totalsGroupSpan;
	@UiField
	DivElement divImage;
	
	@UiField(provided = true)
	CellTable<ContentTypeElementDefinitionRPCProxy> cellTable;
	ContentTypeProxy selectedContentTypeProxy;
	Map<Integer, ContentTypeElementDefinitionRPCProxy> pendingChange = new HashMap<Integer,ContentTypeElementDefinitionRPCProxy>();
	
	private List<AbstractEditableCell<?, ?>> editableCells;
	public static final ProvidesKey<ContentTypeElementDefinitionRPCProxy> KEY_PROVIDER = new ProvidesKey<ContentTypeElementDefinitionRPCProxy>() {
		public Object getKey(ContentTypeElementDefinitionRPCProxy item) {
			return item == null ? null : item.getId();
		}
	};
	
	private ListDataProvider<ContentTypeElementDefinitionRPCProxy> dataProvider = new ListDataProvider<ContentTypeElementDefinitionRPCProxy>();
	
	final NhimCMSAdminRequestFactory requestFactory;
	MessageManager message = new MessageManager();
	Boolean isNew = true;
	private final ContentTypeElementDefinitionRPCServiceAsync service = GWT
	.create(ContentTypeElementDefinitionRPCService.class);
	public ContentType(final NhimCMSAdminRequestFactory requestFactory) {
		this.requestFactory = requestFactory;
		createTable();
		initWidget(uiBinder.createAndBindUi(this));
		editPanel.setVisible(false);
		overviewPanel.setVisible(true);
		btnDelete.setVisible(false);
		btnSave.setVisible(false);
		divImage.setInnerHTML(AbstractImagePrototype.create(
				Styles.resources().contentType()).getHTML());
		
		
	}

	public String mayStop() {
		return null;
	}

	public void onCancel() {

	}

	public void onStop() {

	}

	public void start(AcceptsOneWidget panel, EventBus eventBus) {
		panel.setWidget(this);

	}
	private void clearForm() {
		txtName.setText("");
		txtDescription.setText("");
		List<ContentTypeElementDefinitionRPCProxy> data = dataProvider.getList();
		data.clear();
		cellTable.redraw();
		 
		
	}
	

	public void updateForPlace(final ContentTypePlace place) {
		// Create a CellList.
		ContentTypeCell groupList = new ContentTypeCell();

		// Set a key provider that provides a unique key for each
		// CustomWidgetInstance. If key is
		// used to identify CustomWidgetInstances when fields (such as the name
		// and description)
		// change.
		contentTypeCellList = new CellList<ContentTypeProxy>(groupList,
				CONTENTTYPE_KEY_PROVIDER);
		contentTypeCellList.setPageSize(30);
		contentTypeCellList.setKeyboardPagingPolicy(KeyboardPagingPolicy.INCREASE_RANGE);
		contentTypeCellList.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.BOUND_TO_SELECTION);

		contentTypeCellList.setSelectionModel(contentTypeSelectionModel);
		contentTypeSelectionModel
				.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
					public void onSelectionChange(SelectionChangeEvent event) {
						 selectedContentTypeProxy = contentTypeSelectionModel.getSelectedObject();
						clearForm();
						isNew = false;
						btnDelete.setVisible(true);
						btnEdit.setVisible(true);
						editPanel.setVisible(true);
						overviewPanel.setVisible(false);
						btnSave.setVisible(true);
						txtName.setText(selectedContentTypeProxy.getName());
						txtDescription.setText(selectedContentTypeProxy
								.getDescription());
						rebindElementDefinition();
						
					}
				});
		pagerPanel.setDisplay(contentTypeCellList);
		contentTypeDataProvider.addDataDisplay(contentTypeCellList);
		rebindContentType();

	}
	private void rebindContentType()
	{
		final List<ContentTypeProxy> data = contentTypeDataProvider.getList();
		requestFactory.contentTypeRequest().findAll()
				.fire(new Receiver<List<ContentTypeProxy>>() {
					@Override
					public void onFailure(ServerFailure error) {
						Window.alert("There was an error while fetching groups.");
					}

					@Override
					public void onSuccess(List<ContentTypeProxy> results) {
						totalsGroupSpan.setInnerText(results.size() + " ContentTypes");
						data.clear();
						data.addAll(results);
					}
				});
		contentTypeCellList.redraw();
	}
	private void rebindElementDefinition()
	{
		service.findByContentTypeId(selectedContentTypeProxy.getId(),new AsyncCallback<ArrayList<ContentTypeElementDefinitionRPCProxy>>() {

			public void onFailure(Throwable e) {
				Window.alert("There was an error while fetching ContentTypeElementDefinition.");

			}

			public void onSuccess(
					ArrayList<ContentTypeElementDefinitionRPCProxy> result) {
				
				List<ContentTypeElementDefinitionRPCProxy> data = dataProvider.getList();
				data.clear();
				data.addAll(result);
				cellTable.redraw();
			}
		});
	}
	
	private void createTable() {
		 // Create the table.
	    editableCells = new ArrayList<AbstractEditableCell<?, ?>>();
	    cellTable = new CellTable<ContentTypeElementDefinitionRPCProxy>(56,KEY_PROVIDER);
	    dataProvider.addDataDisplay(cellTable);
	    // TextCell.
	    addColumn(new TextCell(), "Element Definition Name", new GetValue<String>() {
	      public String getValue(ContentTypeElementDefinitionRPCProxy ctype) {
	    	  return ctype.getElementDefinitionName();
	      }
	    }, null);
	    
	
	    addColumn(new CheckboxCell(), "Is Required", new GetValue<Boolean>() {
	      public Boolean getValue(ContentTypeElementDefinitionRPCProxy ctype) {
	        return ctype.getIsRequired();
	      }
	    }, new FieldUpdater<ContentTypeElementDefinitionRPCProxy, Boolean>() {
		      public void update(int index, ContentTypeElementDefinitionRPCProxy object, Boolean value) {
			       object.setIsRequired(value);
			       pendingChange.put(object.getId(), object);
		      }
		    });
	    
	    addColumn(new TextCell(), "Meta Data", new GetValue<String>() {
		      public String getValue(ContentTypeElementDefinitionRPCProxy ctype) {
		    	  if(ctype.getIsMetadata())
		    		  	return "Yes";
		    	  else
		    		  return "No";
		      }
		    }, null);
	 // TextInputCell.
	    addColumn(new TextInputCell(), "Description", new GetValue<String>() {
	      public String getValue(ContentTypeElementDefinitionRPCProxy ctype) {
	        return ctype.getDescription();
	      }
	    }, new FieldUpdater<ContentTypeElementDefinitionRPCProxy, String>() {
	      public void update(int index, ContentTypeElementDefinitionRPCProxy object, String value) {
	        object.setDescription(value);
	        pendingChange.put(object.getId(), object);
	      }
	    });
	}

	
	/**
	 * Get a cell value from a record.
	 * 
	 * @param <C>
	 *            the cell type
	 */
	private static interface GetValue<C> {
		C getValue(ContentTypeElementDefinitionRPCProxy tempate);
	}
	/**
	   * Add a column with a header.
	   *
	   * @param <C> the cell type
	   * @param cell the cell used to render the column
	   * @param headerText the header string
	   * @param getter the value getter for the cell
	   */
	  private <C> Column<ContentTypeElementDefinitionRPCProxy, C> addColumn(Cell<C> cell, String headerText,
	      final GetValue<C> getter, FieldUpdater<ContentTypeElementDefinitionRPCProxy, C> fieldUpdater) {
	    Column<ContentTypeElementDefinitionRPCProxy, C> column = new Column<ContentTypeElementDefinitionRPCProxy, C>(cell) {
	      @Override
	      public C getValue(ContentTypeElementDefinitionRPCProxy object) {
	        return getter.getValue(object);
	      }
	    };
	    column.setFieldUpdater(fieldUpdater);
	    if (cell instanceof AbstractEditableCell<?, ?>) {
	      editableCells.add((AbstractEditableCell<?, ?>) cell);
	    }
	    cellTable.addColumn(column, headerText);
	    return column;
	  }
	  

		/**
		 * The Cell used to render a {@link GroupCell}.
		 */
		static class ContentTypeCell extends AbstractCell<ContentTypeProxy> {

			public ContentTypeCell() {

			}

			@Override
			public void render(com.google.gwt.cell.client.Cell.Context arg0,
					ContentTypeProxy value, SafeHtmlBuilder sb) {

				// Value can be null, so do a null check..
				if (value == null) {
					return;
				}

				sb.appendHtmlConstant("<table>");

				// Add the content type image.
				sb.appendHtmlConstant("<tr>");

				// Add the name and description.
				sb.appendHtmlConstant("<td style='font-size:95%;'>");
				sb.appendEscaped(value.getName());
				sb.appendHtmlConstant("</td></tr><tr><td style='text-align: right; font-style: italic; color: #666666;'>");
				sb.appendEscaped(value.getDescription());
				sb.appendHtmlConstant("</td></tr></table>");
			}

		}

		/**
		 * The CellList.
		 */
		private CellList<ContentTypeProxy> contentTypeCellList;
		// Add a selection model so we can select cells.
		SingleSelectionModel<ContentTypeProxy> contentTypeSelectionModel = new SingleSelectionModel<ContentTypeProxy>(
				CONTENTTYPE_KEY_PROVIDER);

		private ListDataProvider<ContentTypeProxy> contentTypeDataProvider = new ListDataProvider<ContentTypeProxy>();

		/**
		 * The key provider that provides the unique ID of a contentType.
		 */
		public static final ProvidesKey<ContentTypeProxy> CONTENTTYPE_KEY_PROVIDER = new ProvidesKey<ContentTypeProxy>() {
			public Object getKey(ContentTypeProxy item) {
				return item == null ? null : item.getId();
			}
		};

		/**
		 * The resources applied to the table.
		 */
		interface TableResources extends CellTable.Resources {
			@Source({ CellTable.Style.DEFAULT_CSS,
					"../../style/normalCellTable.css" })
			TableStyle cellTableStyle();
		}

		/**
		 * The styles applied to the table.
		 */
		interface TableStyle extends CellTable.Style {

		}
		
		@UiHandler("btnEdit")
		void handleButtonCancelClick(ClickEvent e) {
			ContentTypeElementDefinitionSelection elementDefinitionSelection = new ContentTypeElementDefinitionSelection(
					selectedContentTypeProxy,requestFactory);
			elementDefinitionSelection.setGlassEnabled(true);
			elementDefinitionSelection.center();
			elementDefinitionSelection.show();
			elementDefinitionSelection.setListener(new Listener(){

				public void onSave() {
					rebindElementDefinition();
					
				}});

		}
		
		@UiHandler("btnNew")
		void handleButtonNewClick(ClickEvent e) {
			
			if(selectedContentTypeProxy != null && (!selectedContentTypeProxy.getName().equalsIgnoreCase(txtName.getText().trim()) ||!selectedContentTypeProxy.getDescription().equalsIgnoreCase(txtDescription.getText().trim())))
			{
				if(Window.confirm("Your changes to this group will be lost if you don't save them."))
					createNew();
			}
			else
				createNew();
			
		
		}
		
		private void createNew()
		{
			btnDelete.setVisible(false);
			btnSave.setVisible(true);
			isNew = true;
			clearForm();
			editPanel.setVisible(true);
			btnEdit.setVisible(false);
			overviewPanel.setVisible(false);
			selectedContentTypeProxy = null;
		}
		@UiHandler("btnSave")
		void handleButtonSaveClick(ClickEvent e) {
			ContentTypeRequest thisRequest = requestFactory.contentTypeRequest();
			final List<ContentTypeProxy> data = contentTypeDataProvider.getList();
			ContentTypeProxy saveContentType;
			if (!isNew) {
				
				data.remove(selectedContentTypeProxy);		
				saveContentType = thisRequest.edit(selectedContentTypeProxy);
			}else
			{
				btnEdit.setVisible(true);
				saveContentType = thisRequest.create(ContentTypeProxy.class);
			}
			saveContentType.setDescription(this.txtDescription.getText());
			saveContentType.setName(this.txtName.getText());
			thisRequest.persit(saveContentType).fire(new Receiver<ContentTypeProxy>() {

				@Override
				public void onSuccess(ContentTypeProxy result) {
					if(result != null)
					{
						selectedContentTypeProxy = result;
						rebindContentType();
						contentTypeSelectionModel.setSelected(selectedContentTypeProxy, true);
						btnDelete.setVisible(true);
					}
				}
			});
				service.persitContentTypeElementDefinitioinsIsRequiredAndDescriptionOnly(new ArrayList<ContentTypeElementDefinitionRPCProxy>(pendingChange.values()),new AsyncCallback<Boolean>() {

					public void onFailure(Throwable e) {
						Window.alert("There was an error while saving ContentTypeElementDefinition.");

					}

					public void onSuccess(
							Boolean result) {
						
						if(result)
							pendingChange.clear();
						else
							Window.alert("There was an error while saving ContentTypeElementDefinition.");
					}
				});

		}
		
		@UiHandler("btnDelete")
		void handleButtonDeleteClick(ClickEvent e) {
			if (Window.confirm("Are you sure you want to delete this ContentType?")) {
				requestFactory.contentTypeRequest().remove(selectedContentTypeProxy.getId())
						.fire(new Receiver<Boolean>() {
							@Override
							public void onFailure(ServerFailure error) {
								Window.alert("There was an error while deleting ContentType.");
							}

							@Override
							public void onSuccess(Boolean result) {	
								rebindContentType();
								editPanel.setVisible(false);
								overviewPanel.setVisible(true);
							}
						});
			}

		}

	
}
